package com.zndroid.base.ui.impl;

import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import androidx.activity.OnBackPressedCallback;
import androidx.activity.OnBackPressedDispatcherOwner;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.IntRange;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.res.ResourcesCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.viewbinding.ViewBinding;

import com.zndroid.base.callback.inner.mvp.IView;
import com.zndroid.base.widgets.HolderView;
import com.zndroid.toast.Toaster;
import com.zndroid.utils.impl.ScreenUtil;

/**
 * ......................我佛慈悲....................
 * ......................_oo0oo_.....................
 * .....................o8888888o....................
 * .....................88" . "88....................
 * .....................(| -_- |)....................
 * .....................0\  =  /0....................
 * ...................___/`---'\___..................
 * ..................' \\|     |// '.................
 * ................./ \\|||  :  |||// \..............
 * .............../ _||||| -卍-|||||- \..............
 * ..............|   | \\\  -  /// |   |.............
 * ..............| \_|  ''\---/''  |_/ |.............
 * ..............\  .-\__  '-'  ___/-. /.............
 * ............___'. .'  /--.--\  `. .'___...........
 * .........."" '<  `.___\_<|>_/___.' >' ""..........
 * ........| | :  `- \`.;`\ _ /`;.`/ - ` : | |.......
 * ........\  \ `_.   \_ __\ /__ _/   .-` /  /.......
 * ....=====`-.____`.___ \_____/___.-`___.-'=====....
 * ......................`=---='.....................
 * ..................佛祖开光 ,永无BUG................
 *
 * @author lzy
 * base fragemnt support permission request
 */
@SuppressWarnings("unused")
public abstract class BaseFragment<VB extends ViewBinding, P extends BasePresenter> extends NetEnableFragment implements
        IView,
        HolderView.OnRetryButtonClickListener
{
    private View view;
    private P mPresenter;
    private VB viewBinding;
    private @NonNull final ScreenUtil screenUtil = new ScreenUtil();

    /**
     * current fragment non-operational
     * @return true or false
     * */
    @Override
    public boolean isDied() {
        return this.isHidden() || !this.isVisible() || this.isDetached();
    }

    private boolean isPresenterReady() {
        return (null != mPresenter) && (mPresenter.isAttached());
    }

    /**
     * if you want intercept 'onBackPressed', Override it at first.
     * @return boolean true: intercept, false: not intercept
     * */
    protected boolean isInterceptBackPressed() {
        return false;
    }

    /**
     * override this fun if you want keep screen on
     *
     * @return true or false, default false and not keep screen on
     */
    protected boolean isKeepScreenOn() {
        return false;
    }

    /**
     * override this fun if you want keep fullscreen
     *
     * @return true or false, default false and not fullscreen
     */
    protected boolean isFullScreen() {
        return false;
    }

    /**
     * control statue bar changed validated, default validated of it's activity
     * <br>
     * See ALso: {@link #onSupplyStatusBarColor()}
     *
     * @return true validate, or false
     * */
    protected boolean isValidateStatueBarColorOfFragment() { return false; }

    /**
     * secure screen or not, if 'false' cannot screen capture， always used by pay or password element
     * <br>Notice:It valid at 'activity'
     * @return true or false
     * */
    protected boolean isScreenCaptureAble() {
        return true;
    }

    /**
     * translucent statusBar, default: false
     * */
    protected boolean isTranslucentStatusBar() {
        return false;
    }

    /**
     * get instance of current Presenter if you supply.
     * you can do something logic use it.
     * */
    protected P currentPresenter() {
        if (null == mPresenter) {
            throw new UnsupportedOperationException("pls implements #onSupplyPresenter() at first.F");
        }
        return mPresenter;
    }

    /**
     * get instance of current ViewBinding if you supply
     *
     * @return VB ViewBinding
     * */
    protected VB currentViewBinding () {
        return viewBinding;
    }

    @Override
    public View currentRootView() {
        return this.view;
    }

    @Override
    public Context currentContext() {
        return requireContext();
    }

    @Override
    public FragmentActivity currentActivity() {
        return requireActivity();
    }

    @Override
    public Intent currentIntent() {
        return requireActivity().getIntent();
    }

    /**
     * if you use Presenter to implements logic, Override it at first.
     * */
    protected P onSupplyPresenter() {
        return null;
    }

    /**
     * must supply layout_id of subclass
     * @deprecated instead of {@link #onSupplyViewBinding(LayoutInflater, ViewGroup)}, strongly recommended replace it.
     * @return LayoutRes id
     * */
    @Deprecated
    @LayoutRes
    @SuppressWarnings("DeprecatedIsStillUsed")
    protected int onSupplyLayoutId() {return -1;}

    /**
     * must supply ViewBinding instance if current page will be impl layout.<br>
     * you should enable support 'ViewBinding' at your module 'build.gradle' like this:
     * <code>
     *     // Android Studio 3.6.0
     *     android {
     *         ...
     *         viewBinding {
     *             enabled = true
     *         }
     *     }
     *
     *     // Android Studio 4.0 +
     *     android {
     *         ...
     *         buildFeatures {
     *             viewBinding = true
     *         }
     *     }
     * </code>
     *
     *
     * @param layoutInflater layoutInflater
     * @param parent ViewGroup parent
     * @return VB instance of ViewBinding
     * */
    protected abstract VB onSupplyViewBinding(@NonNull LayoutInflater layoutInflater, @Nullable ViewGroup parent);

    @Override
    public HolderView onSupplyPlaceholder() {
        return null;
    }

    /**
     * support change StatusBar color and override {@link #isValidateStatueBarColorOfFragment()} is true
     * <br>
     * See ALso: {@link #isValidateStatueBarColorOfFragment()}
     *
     * @return ColorInt
     * */
    @ColorInt
    protected int onSupplyStatusBarColor(){ return ResourcesCompat.getColor(getResources(), android.R.color.black, requireActivity().getTheme());}

    /**
     * support {@link androidx.appcompat.widget.Toolbar}
     *
     * notice:change Theme must already has not an action bar
     * */
    protected Toolbar onSupplyToolBar(){return null;}

    /**
     * invalidate keep screen on, you can call this to clear keep screen on flag
     */
    protected void toNotKeepScreenOn() {
        requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    /**
     * invalidate fullscreen, you can call this to clear fullscreen on flag
     */
    protected void toNotFullScreen() {
        requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

    /**
     * hide or show StatusBars
     * @param hide true or false
     * */
    public void toChangeStatusBars(boolean hide) {
        if (hide) {
            screenUtil.hideStatusBar(requireActivity());
        } else {
            screenUtil.showStatusBar(requireActivity());
        }
    }

    /**
     * change statusBar color, only support pure color
     * @param color colorInt
     * @param alpha alpha
     * */
    public void toChangeStatusBarColor(@ColorInt int color, @IntRange(from = 0L,to = 255L) int alpha) {
        if (isValidateStatueBarColorOfFragment()) {
            screenUtil.setStatusBarColor(requireActivity(), color, alpha);
        } else {
            logW("you maybe want change 'StatusBar' color, but '#isValidateStatueBarColorOfFragment' is 'false', it will not be validate");
        }
    }

    /**
     * transparent StatusBar
     * */
    public void toTransparentStatusBar() {
        screenUtil.transparentStatusBar(requireActivity());
    }

    /**
     * hide or show NavigationBars
     * @param hide true or false
     * */
    public void toChangeNavigationBars(boolean hide) {
        if (hide) {
            screenUtil.hideNavigationBar(requireActivity());
        } else {
            screenUtil.showNavigationBar(requireActivity());
        }
    }

    @Override
    public void toDismissPlaceholder() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().showSuccess();
        }
    }

    /**
     * to support ScreenCapture or not
     *
     * @param enable true:support false not support
     * */
    protected void toScreenCaptureEnable(boolean enable) {
        if (!enable) {
            requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
        } else {
            requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
        }
    }

    @Override
    public void onBackRetryClicked(View v) {

    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        if (null != onSupplyPresenter()) {
            mPresenter = onSupplyPresenter();
            mPresenter.attachView(this);
        }
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        viewBinding = onSupplyViewBinding(inflater, container);

        if (null == viewBinding) {
            this.view = inflater.inflate(onSupplyLayoutId(), container, false);
        } else {
            this.view = viewBinding.getRoot();
        }

        doOnInitView(view);
        return view;
    }

    @Override
    public void onStart() {
        super.onStart();
        doOnStart();
    }

    @Override
    public void onResume() {
        super.onResume();

        //StatusBar fixed：当跳转其他改变状态栏的页面返回时，当前页面的状态栏不会恢复的bug
        if (isValidateStatueBarColorOfFragment()) {
            if (isTranslucentStatusBar()) {
                screenUtil.transparentStatusBar(requireActivity());
            } else {
                screenUtil.setStatusBarColor(requireActivity(), onSupplyStatusBarColor());
            }
        }
        doOnResume();
    }

    @Override
    public void onPause() {
        doOnPause();
        super.onPause();
    }

    @Override
    public void onStop() {
        doOnStop();
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        viewBinding = null;
    }

    @Override
    public void onDestroy() {
        doOnDestroy();
        super.onDestroy();
    }

    @Override
    public void onDetach() {
        super.onDetach();

        if (isPresenterReady()) {
            mPresenter.detachView();
        }
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        //////for inner function start

        //ToolBar
        if (requireActivity() instanceof AppCompatActivity) {
            AppCompatActivity appCompatActivity = (AppCompatActivity)requireActivity();
            if (null == appCompatActivity.getSupportActionBar()) {
                //- 如果Parent的`setHasOptionsMenu(false)`, Child为true, 则Parent的`onCreateOptionsMenu()`不会调用, 打开Child的时候Activity -> Child.
                //- 如果Child的`setHasOptionsMenu(false)`, Parent为true, 则打开Child的时候仍然会调用Activity和Parent的onCreateOptionsMenu()方法.
                //- 如果Parent和Child都置为false, 打开Parent和Child Fragment的时候都会调用Activity的onCreateOptionsMenu()方法.
                setHasOptionsMenu(true);
                appCompatActivity.setSupportActionBar(onSupplyToolBar());
            } else {
                logW("Tips from " + BaseFragment.class.getSimpleName() +
                        ": This Activity already has an action bar, \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +
                        "  If you want instead of [ToolBar], Do not request 'Window.FEATURE_SUPPORT_ACTION_BAR' \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +
                        "  and set '<item name=\"android:windowActionBar\">false</item>' in your theme style.");
            }
        }
        //onBack Press
        ((OnBackPressedDispatcherOwner)requireActivity())
                .getOnBackPressedDispatcher()
                .addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(isInterceptBackPressed()) {
                    @Override
                    public void handleOnBackPressed() {
                        //pre do something when back pressed
                        doPreOnBackPressed();

                        //do something when back pressed
                        doOnBackPressed();

                        if (isPresenterReady()) {
                            //did something when back pressed
                            mPresenter.didOnBackPressed();
                        }
                    }
                });
        //KeepScreenOn
        if (isKeepScreenOn()) {
            requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        } else {
            requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
        //FullScreen
        if (isFullScreen()) {
            requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        } else {
            requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }
        //ScreenCapture able?
        if (!isScreenCaptureAble()) {
            requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
        } else {
            requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
        }
        //////for inner function end

        doOnCreate(savedInstanceState);

        //all view ok
        doOnInitViewAfterAllReady(currentRootView());
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        doOnConfigurationChanged(newConfig);
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        doSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    /**
     * onStart
     * */
    protected void doOnStart() {}

    /**
     * onCreate
     * */
    protected void doOnCreate(@Nullable Bundle savedInstanceState) {}

    /**
     * onResume
     * */
    protected void doOnResume() {}

    /**
     * onPause
     * */
    protected void doOnPause() {}

    /**
     * onStop
     * */
    protected void doOnStop() {}

    /**
     * onDestroy
     * */
    protected void doOnDestroy() {}

    /**
     * onConfigurationChanged
     * */
    protected void doOnConfigurationChanged(@NonNull Configuration newConfig) {}

    /**
     * onSaveInstanceState
     * */
    protected void doSaveInstanceState(@NonNull Bundle outState) {}

    /**
     * onPreBackPressed
     * */
    protected void doPreOnBackPressed() {}

    /**
     * onBackPressed
     * */
    protected void doOnBackPressed() {}

    /**
     * 此回调方法适用于：布局中控件都是静态布局好的状态，没有动态地在父布局的基础上继续添加其他子布局。否则，
     * 当想在此初始化【在父布局的基础上继续添加其他子布局】中的控件时，会抛出空指针异常，
     * 因为此方法回调的时候，【在父布局的基础上继续添加其他子布局】中的动态子布局还没被append父布局中，
     * 建议使用 {@link #doOnInitViewAfterAllReady(View)}，此方法在后期版本中仍然保留，以适用于不同情况。<br>
     *
     * you can init View(findViewById) here，but, all child view is static layout
     * */
    protected void doOnInitView(View rootView) {}

    /**
     * you can init View(findViewById) here, all view is ready.
     * See ALso: {@link #doOnInitView(View)}
     * */
    protected void doOnInitViewAfterAllReady(View rootView) {}

    @Override
    public void showToast(String msg) {
        if (isDied()) {return;}
        if (!Toaster.isInit()) {
            Toaster.init(requireActivity().getApplication());
        }
        Toaster.show(msg);
    }

    @Override
    public void showEmptyData() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showEmpty();
        }
    }

    @Override
    public void showErrorData() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showError();
        }
    }

    @Override
    public void showNetError() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showBadNet();
        }
    }

    @Override
    public void showLoading() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showWait();
        }
    }

    @Override
    public void showLoading(String msg) {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showWait(msg);
        }
    }

    @Override
    public void showLoading(String msg, boolean cancelable) {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showWait(msg, cancelable);
        }
    }

    @Override
    public void show404() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().show404();
        }
    }

    @Override
    public void showTip(@DrawableRes int resId, String msg) {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showTip(resId, msg);
        }
    }

    @Override
    public void showTip(@DrawableRes int resId, String msg, boolean isShowRetry) {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showTip(resId, msg, isShowRetry);
        }
    }

    /**
     * jump other intent page<br>
     *
     * See Also: {@link #toActivityCallBackAble(Intent)}
     *
     * @param clazz class will be jump
     * */
    @Override
    public void jumpTo(@NonNull Class<?> clazz) {
        jumpTo(new Intent(requireActivity(), clazz));
    }

    /**
     * jump other intent page<br>
     *
     * See Also: {@link #toActivityCallBackAble(Intent)}
     *
     * @param intent intent will be jump
     * */
    @Override
    public void jumpTo(@Nullable Intent intent) {
        startActivity(intent);
    }

    /**
     * jump other intent page<br>
     *
     * See Also: {@link #toActivityCallBackAble(Intent)}
     *
     * @param intent intent will be jump
     * @param bundle params with intent
     * */
    @Override
    public void jumpTo(@Nullable Intent intent, @Nullable Bundle bundle) {
        if (null != intent) {
            intent.putExtras(bundle);
        }
        jumpTo(intent);
    }

    @Override
    public void jumpTo(@Nullable Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode);
    }

    @Override
    public void jumpTo(@Nullable Intent intent, @Nullable Bundle bundle, int requestCode) {
        if (null != intent) {
            intent.putExtras(bundle);
        }

        startActivityForResult(intent, requestCode);
    }

    /**
     * Return the arguments supplied when the fragment was instantiated,
     * if any.
     *
     * See Also: {@link #getArguments()}
     */
    @Override
    public Bundle getBundleArgs() {
        return getArguments();
    }
}
